package com.ops.uitl.jdbc;

import java.io.StringReader;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;
import org.apache.log4j.Logger;

public class ParameterStatement implements IStatement {
	
	protected final Logger log = Logger.getLogger(this.getClass());
	
	private PreparedStatement statement;
	private String sql;
	private Parameter param;
	private Parameter[] params;
	
	/**
	 * construct function
	 * @param conn
	 * @param sqlstr
	 * @throws Exception
	 */
	public ParameterStatement(Connection conn, String sqlstr, Parameter param) throws Exception {
		statement = conn.prepareStatement(sqlstr);
		this.sql = sqlstr;
		this.param = param;
	}
	
	/**
	 * construct function
	 * @param conn
	 * @param sql
	 * @param params
	 * @throws Exception
	 */
	public ParameterStatement(Connection conn, String sqlstr, Parameter[] params) throws Exception {
		statement = conn.prepareStatement(sqlstr);
		this.sql = sqlstr;
		this.params = params;
	}
		
	/**
	 * get sql
	 * @return String
	 * @throws Exception
	 */
    public String getSql() throws Exception {
    	return sql;
    }

	/**
	 * get statement
	 * @return Statement
	 * @throws Exception
	 */
    public Statement getStatement() throws Exception {
    	return statement;
    }

	/**
	 * execute query
	 * @return ResultSet
	 * @throws Exception
	 */
    public ResultSet executeQuery() throws Exception {
    	if (log.isDebugEnabled()) log.debug("SQL " + sql);
    	if (log.isDebugEnabled()) log.debug("PARAM " + param);
    	
    	setParameters(statement, param);
    	
    	try {
    		long beginTime = System.currentTimeMillis();
    		ResultSet result = statement.executeQuery();
    		DaoHelper.getExecuteTimeBySql(log, beginTime);
    		return result;
    	} catch (java.sql.SQLException e) {
    		log.error("ERROR SQL " + sql);
    		throw e;
	    }
    }
    
    /**
     * execute update
     * @return int
     * @throws Exception
     */
    public int executeUpdate() throws Exception {
    	if (log.isDebugEnabled()) log.debug("SQL " + sql);
    	if (log.isDebugEnabled()) log.debug("PARAM " + param);
    	
    	setParameters(statement, param);
    	
    	try {
    		long beginTime = System.currentTimeMillis();
    		int result = statement.executeUpdate();
    		DaoHelper.getExecuteTimeBySql(log, beginTime);
    		return result;
    	} catch (java.sql.SQLException e) {
    		log.error("ERROR SQL " + sql);
    		throw e;
    	}
    }
    
    /**
     * execute batch
     * @return int[]
     * @throws Exception
     */
    public int[] executeBatch() throws Exception {
    	if (params.length == 0) return new int[] {};
    	
    	if (log.isDebugEnabled()) log.debug("Batch SQL " + sql);
    	
	    for (int i=0; i<params.length; i++) {
	    	setParameters(statement, params[i]);
	    	if (log.isDebugEnabled()) log.debug("Batch PARAM " + params[i]);
	    	statement.addBatch();
	    }
	    
	    try {
	    	long beginTime = System.currentTimeMillis();
	    	int[] result = statement.executeBatch();
	    	DaoHelper.getExecuteTimeBySql(log, beginTime);
	    	return result;
    	} catch (java.sql.SQLException e) {
    		log.error("ERROR Batch SQL " + sql);
    		throw e;
    	}
    }

	/**
	 * close statement
	 * @throws Exception
	 */
	public void close() throws Exception {
		statement.close();
	}
	
	/**
	 * set parameters
	 * @param statement
	 * @param param
	 * @throws Exception
	 */
	public void setParameters(PreparedStatement statment, Parameter param) throws Exception {
    	for (int i=0; i<param.size(); i++) {
    		if (param.get(i) == null) {
    			statement.setNull(i + 1, Types.VARCHAR);
    		} else {
    			Object value = param.get(i);
    			if (value instanceof ColumnObject) {
    				ColumnObject columnObject = (ColumnObject) value;
    				if (columnObject.getType() == Types.LONGVARCHAR) {
    					statement.setCharacterStream(i + 1, new StringReader(columnObject.getValue().toString()), columnObject.getValue().toString().length());
    				}
    			} else {
    				statement.setObject(i + 1, value);
    			}
    		}
    	}
	}
		
}